/**
 * 
 */
package com.gragra.sampling.nonproj.structures.projective.singleroot;
import java.util.BitSet;
import com.gragra.sampling.PopulationProbabilityAssigner;
import com.gragra.sampling.ThreadedUniformAccess;
import com.gragra.sampling.binary.ConvertSample;
import com.gragra.sampling.sequentialStructure.WordAndTagHolder;
/**
 * @author Christoph Teichmann
 * 11.10.2013
 */
public class GibbsMHSingleRootProjective extends
		MHMHSingleRootProjectiveDepdTree
{
	/**
	 * 
	 */
	private final double[][] probs;
	/**
	 * @param wth
	 * @param threads
	 * @param cs
	 */
	public GibbsMHSingleRootProjective(WordAndTagHolder wth, int threads,
			ConvertSample cs)
	{
		super(wth, threads, cs);
		probs = new double[threads][this.getLength()+1];
	}
	/**
	 * 
	 * @param thread
	 * @return
	 */
	protected double[] getProbsHolder(int thread)
	{return this.probs[thread];}
	/* (non-Javadoc)
	 * @see com.gragra.sampling.nonproj.structures.projective.singleroot.MHMHSingleRootProjectiveDepdTree#resampleAtPosition(int, com.gragra.sampling.PopulationProbabilityAssigner, double, int, com.gragra.sampling.ThreadedUniformAccess)
	 */
	@Override
	protected void resampleAtPosition(int pos,
			PopulationProbabilityAssigner pa, double annealing, int thread,
			ThreadedUniformAccess tua)
	{
		double[] ps = this.getProbsHolder(thread);
		BitSet bs = this.makeAllHeadCandidates(pos, thread, pa);
		double max = Double.NEGATIVE_INFINITY;
		for(int head=bs.nextSetBit(0);head>=0;head = bs.nextSetBit(head+1))
		{
			this.setNewHead(pos, head, thread);
			max = Math.max(ps[head] = this.makeLogProbForThisConsideringAnnealing(pa, annealing, thread),max);
		}
		double sum = 0.0;
		for(int head=bs.nextSetBit(0);head>=0;head = bs.nextSetBit(head+1))
		{sum += ps[head] = Math.exp(ps[head]-max);}
		int choice = -1;
		double border = tua.nextDouble(thread);
		for(int head=bs.nextSetBit(0);head>=0;head = bs.nextSetBit(head+1))
		{
			border -= ps[head]/sum;
			if(border <= 0.0)
			{
				choice = head;
				break;
			}
		}
		if(choice < 0)
		{throw new IllegalStateException("Probabilities did not sum to one.");}
		this.setNewHead(pos, choice, thread);
	}
}